package wsmsg

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/tidwall/gjson"
	"github.com/tidwall/sjson"
	"hass.tree.com/bridge/sysConfig"
	"hass.tree.com/bridge/utils"
	"hass.tree.com/bridge/utils/websocket"
)

var HassWsHelper *websocket.WebSocketHelper
var bizTransTag sync.Map
var routersMap map[string]string

var ServerWsHelper *websocket.WebSocketHelper
var accessToken string
var refreshToken string

type MsgHandler func(msg string)

func InitConnection(url string) (*websocket.WebSocketHelper, error) {
	ws := &websocket.WebSocketHelper{}
	err := ws.Connect(url)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return ws, nil
}

func ReceiveMsg(ws websocket.WebSocketHelper, code int, handler MsgHandler) {
	errorSum := 5
	errorTimes := 0
	for {
		message, err := ws.ReceiveMessage()
		if err != nil {
			fmt.Println(err)
			time.Sleep(2000 * time.Millisecond)
			errorTimes++
			if errorTimes > errorSum {
				ws.Close()
				InitWs(code)
				return
			}
			continue
		}
		if len(message) == 0 {
			time.Sleep(200 * time.Millisecond)
			continue
		}
		handler(string(message))
	}
}

func hassHandler(msg string) {
	fmt.Println("hassHandler: ", msg)

	bizType := gjson.Get(msg, "type")
	if bizType.Exists() {
		switch bizType.String() {
		case "auth_required":
			authMsg := `{"type":"auth","access_token":"` + sysConfig.AllConfig.Websocket.HassToken + `"}`
			SendMsg(*HassWsHelper, authMsg)
		case "auth_ok":
			bizId := utils.Snowflake.GetId()
			subscribeMsg := fmt.Sprintf(`{"id":%d,"type":"subscribe_events","event_type":"state_changed"}`, bizId)

			SendMsg(*HassWsHelper, subscribeMsg)
		default:
			sendServerMessageHttp(msg)

		}
	}
}

func serverHandler(msg string) {
	fmt.Println("serverHandler: ", msg)
	bizId := utils.Snowflake.GetId()
	sendmsg, err := sjson.Set(msg, "id", bizId)
	if err != nil {
		fmt.Println(err)
		return
	}
	sendErr := SendMsg(*HassWsHelper, sendmsg)
	if sendErr == nil {
		setBizTag(bizId, gjson.Get(msg, "type").String())
	}
}

func SendMsg(ws websocket.WebSocketHelper, msg string) error {
	fmt.Println("hass SendMsg: ", msg)
	err := ws.SendMessage(msg)
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

func InitWs(code int) {
	switch code {
	case 0:
		initServerWs()
		initHassWs()
		go func() {
			for {
				time.Sleep(6 * time.Hour)
				refreshTokenApi()
			}
		}()
	case 1:
		initServerWs()

	case 2:
		initHassWs()

	}
}

func initHassWs() {
	var err error

	for {
		HassWsHelper, err = InitConnection(sysConfig.AllConfig.Websocket.HassUrl)
		if err == nil {
			break
		}
		fmt.Println("hass websocket连接失败，正在重试", err)
		time.Sleep(10 * time.Second)
	}

	fmt.Println("websocket连接Hass服务成功，开始接收消息！")
	go ReceiveMsg(*HassWsHelper, 2, hassHandler)
}
func initServerWs() {

	var err error
	for {
		err = getAccessToken()
		if err != nil {
			fmt.Println("getAccessToken错误:", err)
		} else {
			ServerWsHelper, err = InitConnection(sysConfig.AllConfig.Websocket.ServerUrl + accessToken)
		}
		if err != nil {
			fmt.Println("server websocket连接失败，正在重试", err)
			time.Sleep(10 * time.Second)
		} else {
			break
		}
	}
	routersMap = make(map[string]string)
	routersMap["config/area_registry/list"] = "/homecenter/hassAreaRegistry/pushAreas"
	routersMap["config/device_registry/list"] = "/homecenter/hassDeviceRegistry/pushDevices"
	routersMap["config/entity_registry/list"] = "/homecenter/hassEntityRegistry/pushEntities"
	routersMap["config/entity_registry/get"] = "/homecenter/hassEntityRegistry/pushEntityDetail"
	routersMap["event"] = "/homecenter/biz/ws/hass/receiveEvent"
	routersMap["get_states"] = "/homecenter/biz/ws/hass/syncState"

	fmt.Println("websocket连接平台服务成功，开始接收消息！")
	go ReceiveMsg(*ServerWsHelper, 1, serverHandler)

}

func getAccessToken() error {
	password, _ := utils.EncryptAESCFB(sysConfig.AllConfig.Platform.Password, sysConfig.AllConfig.Platform.Key)
	res, err := utils.PostFormData(sysConfig.AllConfig.Platform.Url+"/auth/oauth2/token?grant_type=password&scope=server",
		map[string]string{
			"Authorization": "Basic " + utils.Base64Encode(sysConfig.AllConfig.Platform.ClientId+":"+sysConfig.AllConfig.Platform.Secret),
		},
		map[string]string{
			"username": sysConfig.AllConfig.Platform.Username,
			"password": password,
		})

	if err != nil {
		return err
	}
	code := gjson.Get(res, "code")
	if code.Exists() && code.Int() == 0 {
		accessToken = gjson.Get(res, "access_token").String()
		refreshToken = gjson.Get(res, "refresh_token").String()
		fmt.Fprintf(os.Stdout, "获取服务平台令牌成功: accessToken: %s, refreshToken: %s\n", accessToken, refreshToken)
		return nil
	} else {
		return fmt.Errorf("获取token失败:" + res)
	}
}

func refreshTokenApi() error {

	res, err := utils.PostFormData(sysConfig.AllConfig.Platform.Url+"/auth/oauth2/token",
		map[string]string{
			"Authorization": "Basic " + utils.Base64Encode(sysConfig.AllConfig.Platform.ClientId+":"+sysConfig.AllConfig.Platform.Secret),
			"skipToken":     "true",
		},
		map[string]string{
			"refresh_token": refreshToken,
			"grant_type":    "refresh_token",
			"scope":         "server",
		})

	if err != nil {
		fmt.Println(err)
		return err
	}
	code := gjson.Get(res, "code")
	if code.Exists() {
		if code.Int() == 0 {
			accessToken = gjson.Get(res, "access_token").String()
			refreshToken = gjson.Get(res, "refresh_token").String()
			fmt.Fprintf(os.Stdout, "刷新服务平台令牌成功: accessToken: %s, refreshToken: %s \n", accessToken, refreshToken)
		}
	}
	return nil
}

func sendServerMessageHttp(msg string) {

	bizType := gjson.Get(msg, "type").String()
	bizId := gjson.Get(msg, "id").Int()
	tag := getBizTag(bizId)

	if tag == "" {
		tag = bizType
	}

	sjson.Set(msg, "bizType", tag)

	uri := routersMap[tag]

	if uri == "" {
		uri = "/homecenter/biz/ws/hass/receiveMessage"
	}

	res, statusCode := utils.PostJsonWithHeader(sysConfig.AllConfig.Platform.Url+uri,
		map[string]string{
			"Authorization": "Bearer " + accessToken,
		}, msg)
	switch statusCode {
	case 200:
		fmt.Fprintf(os.Stdout, "数据推送平台成功: %s\n", msg)

	case 401:
	case 424:
		err := getAccessToken()
		if err != nil {
			fmt.Fprintf(os.Stdout, "getAccessToken: %s\n", err)
			return
		}
		sendServerMessageHttp(msg)

	default:
		fmt.Fprintf(os.Stdout, "错误 %d, 数据推送平台失败：%s\n", statusCode, res)

	}
}

func setBizTag(id int64, tag string) {
	bizTransTag.Store(id, tag)
}

func getBizTag(id int64) string {
	value, isok := bizTransTag.Load(id)
	if isok {
		bizTransTag.Delete(id)
	} else {
		return ""
	}
	return value.(string)
}
